#include "heap.h"

#define SWAP(a, b, size)						      \
	do									      \
		{								      \
		register size_t __size = (size);					      \
		register char *__a = (a), *__b = (b);				      \
		do								      \
		{								      \
		char __tmp = *__a;						      \
		*__a++ = *__b;						              \
		*__b++ = __tmp;						      \
		} while (--__size > 0);						      \
		} while (0)

void PD_Heap_go_down(void *base, int i, int size_heap, size_t size, int (*comparator) (const void *, const void *));
void PD_Heap_go_up(void *base, int i, int size_heap, size_t size, int (*comparator) (const void *, const void *));


void PD_Heap_go_down(void *base, int i, int size_heap, size_t size, int (*comparator) (const void *, const void *))
{
    int k = 0;
    int f;
    f = (2 * i + 1);
    if (f < size_heap) {

	if (f + 1 < size_heap) {
	    if (comparator((void *) (base + size * f + 1 * size), (void *) (base + size * f)) >= 0)

		f++;
	}

	if (comparator((void *) (base + size * f), (void *) (base + size * i)) >= 0) {
	    SWAP((void *) (base + size * f), (void *) (base + size * i), size);
	    PD_Heap_go_down(base, f, size_heap, size, comparator);
	}
    }
}
void PD_Heap_heapify(void *base, int n, size_t size, int (*comparator) (const void *, const void *))
{
    int i = 0;
    i = floor(n / 2);
    while (i >= 0) {
	PD_Heap_go_down(base, i, n, size, comparator);
	i--;
    }

}
void PD_Heap_go_up(void *base, int i, int size_heap, size_t size, int (*comparator) (const void *, const void *))
{
    int j;

    if (i > 0) {
	if ((i % 2) == 0) {
	    j = floor((i / 2) - 1);
	}

	else
	    j = floor(i / 2);

	if (comparator((void *) (base + size * i), (void *) (base + size * j)) >= 0)
	{

	    SWAP((void *) (base + size * i), (void *) (base + size * j), size);

	    PD_Heap_go_up(base, j, size_heap, size, comparator);

	}
    }
}
void PD_Heap_insert(void *base, int new, int old, int size_heap, size_t size, int (*comparator) (const void *, const void *))
{

    if (size_heap > 0) {

	SWAP((void *) (base + size * (new)), (void *) (base + size * (old)), size);
	PD_Heap_go_up(base, old, size_heap, size, comparator);
    }
}
void PD_Heap_remove(void *base, int size_heap, size_t size, int (*comparator) (const void *, const void *))
{
    if (size_heap > 0) {

	SWAP((void *) base + size * 0, (void *) base + size * (size_heap - 1), size);

	PD_Heap_go_down(base, 0, size_heap - 2, size, comparator);
    }
}
